/*     */ package com.zimbra.cs.lmtpserver;
/*     */ 
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.stats.Counter;
/*     */ import com.zimbra.common.util.ByteUtil;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.StringUtil;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.account.Server;
/*     */ import com.zimbra.cs.server.ProtocolHandler;
/*     */ import com.zimbra.cs.server.ServerThrottle;
/*     */ import com.zimbra.cs.stats.ZimbraPerf;
/*     */ import java.io.IOException;
/*     */ import java.net.InetAddress;
/*     */ import java.util.Date;
/*     */ import java.util.List;
/*     */ import javax.mail.internet.MailDateFormat;
/*     */ import javax.mail.internet.MimeUtility;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public abstract class LmtpHandler
/*     */   extends ProtocolHandler
/*     */ {
/*     */   final LmtpConfig config;
/*     */   protected LmtpWriter mWriter;
/*     */   protected String mRemoteAddress;
/*     */   protected String mRemoteHostname;
/*     */   private String mLhloArg;
/*     */   protected LmtpEnvelope mEnvelope;
/*     */   private String mCurrentCommandLine;
/*     */   private final ServerThrottle throttle;
/*     */   protected boolean lhloIssued;
/*     */   protected boolean startedTLS;
/*     */   protected boolean lhloIssuedAfterStartTLS;
/*     */   
/*     */   LmtpHandler(LmtpServer server)
/*     */   {
/*  54 */     super((server instanceof TcpLmtpServer) ? (TcpLmtpServer)server : null);
/*  55 */     this.config = server.getConfig();
/*  56 */     this.throttle = ServerThrottle.getThrottle(this.config.getProtocol());
/*     */   }
/*     */   
/*     */   protected boolean setupConnection(InetAddress remoteAddr) {
/*  60 */     this.mRemoteAddress = remoteAddr.getHostAddress();
/*  61 */     if (StringUtil.isNullOrEmpty(this.mRemoteAddress))
/*     */     {
/*  63 */       ZimbraLog.lmtp.info("Unable to determine client IP address.");
/*     */     }
/*  65 */     this.mRemoteHostname = remoteAddr.getHostName();
/*  66 */     if ((this.mRemoteHostname == null) || (this.mRemoteHostname.length() == 0)) {
/*  67 */       this.mRemoteHostname = this.mRemoteAddress;
/*     */     }
/*  69 */     ZimbraLog.addIpToContext(this.mRemoteAddress);
/*  70 */     ZimbraLog.lmtp.debug("connected");
/*  71 */     if (!this.config.isServiceEnabled()) {
/*  72 */       sendReply(LmtpReply.SERVICE_DISABLED);
/*  73 */       dropConnection();
/*  74 */       return false;
/*     */     }
/*  76 */     sendReply(LmtpReply.GREETING);
/*  77 */     return true;
/*     */   }
/*     */   
/*     */   protected void notifyIdleConnection()
/*     */   {
/*  82 */     sendReply(LmtpReply.TIMEOUT);
/*     */   }
/*     */   
/*     */ 
/*     */   protected boolean authenticate()
/*     */   {
/*  88 */     return true;
/*     */   }
/*     */   
/*     */   protected boolean processCommand(String cmd) throws IOException {
/*  92 */     ZimbraLog.addIpToContext(this.mRemoteAddress);
/*  93 */     this.mCurrentCommandLine = cmd;
/*  94 */     String arg = null;
/*     */     
/*  96 */     if (cmd == null) {
/*  97 */       ZimbraLog.lmtp.info("disconnected without quit");
/*  98 */       dropConnection();
/*  99 */       return false;
/*     */     }
/*     */     
/* 102 */     ZimbraLog.lmtp.trace("C: %s", new Object[] { cmd });
/*     */     
/* 104 */     if (!this.config.isServiceEnabled()) {
/* 105 */       sendReply(LmtpReply.SERVICE_DISABLED);
/* 106 */       dropConnection();
/* 107 */       return false;
/*     */     }
/*     */     
/* 110 */     if (this.throttle.isIpThrottled(this.mRemoteAddress)) {
/* 111 */       ZimbraLog.lmtp.warn("throttling LMTP connection for remote IP %s", new Object[] { this.mRemoteAddress });
/* 112 */       dropConnection();
/* 113 */       return false;
/*     */     }
/*     */     
/* 116 */     setIdle(false);
/*     */     
/* 118 */     int i = cmd.indexOf(' ');
/* 119 */     if (i > 0) {
/* 120 */       arg = cmd.substring(i + 1);
/* 121 */       cmd = cmd.substring(0, i);
/*     */     }
/*     */     
/* 124 */     if (cmd.length() < 4) {
/* 125 */       doSyntaxError();
/* 126 */       return true;
/*     */     }
/*     */     
/* 129 */     int ch = cmd.charAt(0);
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 135 */     switch (ch)
/*     */     {
/*     */     case 76: 
/*     */     case 108: 
/* 139 */       if ("LHLO".equalsIgnoreCase(cmd)) {
/* 140 */         doLHLO(arg);
/* 141 */         return true;
/*     */       }
/*     */       
/*     */       break;
/*     */     case 77: 
/*     */     case 109: 
/* 147 */       if (tlsConnectionRequired()) {
/* 148 */         sendReply(LmtpReply.TLS_REQUIRED);
/* 149 */         dropConnection();
/* 150 */         return true;
/*     */       }
/* 152 */       if (missingLHLO()) {
/* 153 */         sendReply(LmtpReply.MISSING_LHLO);
/* 154 */         dropConnection();
/* 155 */         return true;
/*     */       }
/* 157 */       if ("MAIL".equalsIgnoreCase(cmd)) {
/* 158 */         int fromColonLength = 5;
/* 159 */         if (arg.length() >= 5)
/*     */         {
/*     */ 
/* 162 */           String fromColon = arg.substring(0, 5);
/* 163 */           if ("FROM:".equalsIgnoreCase(fromColon))
/*     */           {
/*     */ 
/* 166 */             arg = arg.substring(5);
/* 167 */             doMAIL(arg);
/* 168 */             return true;
/*     */           }
/*     */         }
/*     */       }
/*     */       break;
/*     */     case 82: case 114: 
/* 174 */       if (tlsConnectionRequired()) {
/* 175 */         sendReply(LmtpReply.TLS_REQUIRED);
/* 176 */         dropConnection();
/* 177 */         return true;
/*     */       }
/* 179 */       if (missingLHLO()) {
/* 180 */         sendReply(LmtpReply.MISSING_LHLO);
/* 181 */         dropConnection();
/* 182 */         return true;
/*     */       }
/* 184 */       if ("RSET".equalsIgnoreCase(cmd)) {
/* 185 */         doRSET(arg);
/* 186 */         return true;
/*     */       }
/* 188 */       if ("RCPT".equalsIgnoreCase(cmd)) {
/* 189 */         int toColonLength = 3;
/* 190 */         if (arg.length() >= 3)
/*     */         {
/*     */ 
/* 193 */           String toColon = arg.substring(0, 3);
/* 194 */           if ("TO:".equalsIgnoreCase(toColon))
/*     */           {
/*     */ 
/* 197 */             arg = arg.substring(3);
/* 198 */             doRCPT(arg);
/* 199 */             return true;
/*     */           }
/*     */         }
/*     */       }
/*     */       break;
/*     */     case 68: case 100: 
/* 205 */       if (tlsConnectionRequired()) {
/* 206 */         sendReply(LmtpReply.TLS_REQUIRED);
/* 207 */         dropConnection();
/* 208 */         return true;
/*     */       }
/* 210 */       if (missingLHLO()) {
/* 211 */         sendReply(LmtpReply.MISSING_LHLO);
/* 212 */         dropConnection();
/* 213 */         return true;
/*     */       }
/* 215 */       if ("DATA".equalsIgnoreCase(cmd)) {
/* 216 */         doDATA();
/* 217 */         return true;
/*     */       }
/*     */       
/*     */       break;
/*     */     case 78: 
/*     */     case 110: 
/* 223 */       if (missingLHLO()) {
/* 224 */         sendReply(LmtpReply.MISSING_LHLO);
/* 225 */         dropConnection();
/* 226 */         return true;
/*     */       }
/* 228 */       if ("NOOP".equalsIgnoreCase(cmd)) {
/* 229 */         doNOOP();
/* 230 */         return true;
/*     */       }
/*     */       
/*     */       break;
/*     */     case 81: 
/*     */     case 113: 
/* 236 */       if ("QUIT".equalsIgnoreCase(cmd)) {
/* 237 */         doQUIT();
/* 238 */         return false;
/*     */       }
/*     */       
/*     */       break;
/*     */     case 83: 
/*     */     case 115: 
/* 244 */       if (missingLHLO()) {
/* 245 */         sendReply(LmtpReply.MISSING_LHLO);
/* 246 */         dropConnection();
/* 247 */         return true;
/*     */       }
/* 249 */       if ("STARTTLS".equalsIgnoreCase(cmd)) {
/* 250 */         doSTARTTLS(arg);
/* 251 */         return true;
/*     */       }
/*     */       
/*     */       break;
/*     */     case 86: 
/*     */     case 118: 
/* 257 */       if (tlsConnectionRequired()) {
/* 258 */         sendReply(LmtpReply.TLS_REQUIRED);
/* 259 */         dropConnection();
/* 260 */         return true;
/*     */       }
/* 262 */       if (missingLHLO()) {
/* 263 */         sendReply(LmtpReply.MISSING_LHLO);
/* 264 */         dropConnection();
/* 265 */         return true;
/*     */       }
/* 267 */       if ("VRFY".equalsIgnoreCase(cmd)) {
/* 268 */         doVRFY(arg);
/* 269 */         return true;
/*     */       }
/*     */       
/*     */       break;
/*     */     }
/*     */     
/*     */     
/* 276 */     doSyntaxError();
/* 277 */     return true;
/*     */   }
/*     */   
/*     */   protected void sendReply(LmtpReply reply) {
/* 281 */     String cl = this.mCurrentCommandLine != null ? this.mCurrentCommandLine : "<none>";
/* 282 */     if (!reply.success()) {
/* 283 */       ZimbraLog.lmtp.info("S: %s (%s)", new Object[] { reply, cl });
/*     */     } else {
/* 285 */       ZimbraLog.lmtp.trace("S: %s (%s)", new Object[] { reply, cl });
/*     */     }
/* 287 */     this.mWriter.println(reply.toString());
/* 288 */     this.mWriter.flush();
/*     */   }
/*     */   
/*     */   protected void doSyntaxError() {
/* 292 */     sendReply(LmtpReply.SYNTAX_ERROR);
/*     */   }
/*     */   
/*     */   private void doNOOP() {
/* 296 */     sendReply(LmtpReply.OK);
/*     */   }
/*     */   
/*     */   private void doQUIT() {
/* 300 */     sendReply(LmtpReply.BYE);
/* 301 */     ZimbraLog.lmtp.debug("quit from client");
/* 302 */     dropConnection();
/*     */   }
/*     */   
/*     */   private void doRSET(String arg) {
/* 306 */     if (arg != null) {
/* 307 */       doSyntaxError();
/* 308 */       return;
/*     */     }
/* 310 */     reset();
/* 311 */     sendReply(LmtpReply.OK);
/*     */   }
/*     */   
/*     */   private void doVRFY(String arg) {
/* 315 */     if ((arg == null) || (arg.length() == 0)) {
/* 316 */       doSyntaxError();
/* 317 */       return;
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 324 */     sendReply(LmtpReply.USE_RCPT_INSTEAD);
/*     */   }
/*     */   
/*     */   private void doLHLO(String arg) {
/* 328 */     this.mLhloArg = arg;
/* 329 */     if ((arg == null) || (arg.length() == 0)) {
/* 330 */       doSyntaxError();
/* 331 */       return;
/*     */     }
/*     */     
/* 334 */     String resp = "250-" + this.config.getServerName() + "\r\n" + "250-8BITMIME\r\n" + "250-ENHANCEDSTATUSCODES\r\n" + (this.startedTLS ? "" : "250-STARTTLS\r\n") + "250-SIZE\r\n" + "250 PIPELINING";
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 340 */     this.mWriter.println(resp);
/* 341 */     this.mWriter.flush();
/* 342 */     reset();
/* 343 */     if (this.startedTLS) {
/* 344 */       this.lhloIssuedAfterStartTLS = true;
/*     */     } else {
/* 346 */       this.lhloIssued = true;
/*     */     }
/*     */   }
/*     */   
/*     */   private void doMAIL(String arg) {
/* 351 */     if ((arg == null) || (arg.length() == 0)) {
/* 352 */       doSyntaxError();
/* 353 */       return;
/*     */     }
/*     */     
/* 356 */     if (this.mEnvelope.hasSender()) {
/* 357 */       sendReply(LmtpReply.NESTED_MAIL_COMMAND);
/* 358 */       return;
/*     */     }
/*     */     
/* 361 */     LmtpAddress addr = new LmtpAddress(arg, new String[] { "BODY", "SIZE" }, null);
/* 362 */     if (!addr.isValid()) {
/* 363 */       sendReply(LmtpReply.INVALID_SENDER_ADDRESS);
/* 364 */       return;
/*     */     }
/*     */     
/* 367 */     LmtpBodyType type = null;
/* 368 */     String body = addr.getParameter("BODY");
/* 369 */     if (body != null) {
/* 370 */       type = LmtpBodyType.getInstance(body);
/* 371 */       if (type == null) {
/* 372 */         sendReply(LmtpReply.INVALID_BODY_PARAMETER);
/* 373 */         return;
/*     */       }
/*     */     }
/*     */     
/* 377 */     int size = 0;
/* 378 */     String sz = addr.getParameter("SIZE");
/* 379 */     if (sz != null) {
/*     */       try {
/* 381 */         size = Integer.parseInt(sz);
/*     */       } catch (NumberFormatException nfe) {
/* 383 */         sendReply(LmtpReply.INVALID_SIZE_PARAMETER);
/* 384 */         return;
/*     */       }
/*     */     }
/*     */     
/* 388 */     this.mEnvelope.setSender(addr);
/* 389 */     this.mEnvelope.setBodyType(type);
/* 390 */     this.mEnvelope.setSize(size);
/* 391 */     sendReply(LmtpReply.SENDER_OK);
/*     */   }
/*     */   
/*     */   private void doRCPT(String arg) {
/* 395 */     if ((arg == null) || (arg.length() == 0)) {
/* 396 */       doSyntaxError();
/* 397 */       return;
/*     */     }
/*     */     
/* 400 */     if (!this.mEnvelope.hasSender()) {
/* 401 */       sendReply(LmtpReply.MISSING_MAIL_TO);
/* 402 */       return;
/*     */     }
/*     */     
/* 405 */     LmtpAddress addr = new LmtpAddress(arg, null, this.config.getMtaRecipientDelimiter());
/* 406 */     if (!addr.isValid()) {
/* 407 */       sendReply(LmtpReply.INVALID_RECIPIENT_ADDRESS);
/* 408 */       return;
/*     */     }
/*     */     
/* 411 */     LmtpReply reply = this.config.getLmtpBackend().getAddressStatus(addr);
/* 412 */     if (reply.success()) {
/* 413 */       if (addr.isOnLocalServer()) {
/* 414 */         this.mEnvelope.addLocalRecipient(addr);
/*     */       } else
/* 416 */         this.mEnvelope.addRemoteRecipient(addr);
/*     */     }
/* 418 */     sendReply(reply);
/*     */   }
/*     */   
/*     */   protected void reset()
/*     */   {
/* 423 */     this.mEnvelope = new LmtpEnvelope();
/* 424 */     this.mCurrentCommandLine = null;
/*     */   }
/*     */   
/*     */   private void doDATA() throws IOException {
/* 428 */     if (!this.mEnvelope.hasRecipients()) {
/* 429 */       sendReply(LmtpReply.NO_RECIPIENTS);
/* 430 */       return;
/*     */     }
/* 432 */     sendReply(LmtpReply.OK_TO_SEND_DATA);
/* 433 */     continueDATA();
/*     */   }
/*     */   
/*     */ 
/*     */   protected abstract void continueDATA()
/*     */     throws IOException;
/*     */   
/*     */   protected void processMessageData(LmtpMessageInputStream in)
/*     */   {
/*     */     try
/*     */     {
/* 444 */       this.config.getLmtpBackend().deliver(this.mEnvelope, in, this.mEnvelope.getSize());
/* 445 */       finishMessageData(in.getMessageSize());
/*     */     } catch (UnrecoverableLmtpException e) {
/* 447 */       ZimbraLog.lmtp.error("Unrecoverable error while handling DATA command.  Dropping connection.", e);
/*     */       try {
/* 449 */         ByteUtil.countBytes(in);
/* 450 */         sendReply(LmtpReply.SERVICE_DISABLED);
/*     */       } catch (IOException e2) {
/* 452 */         ZimbraLog.lmtp.warn("Unable to drain stream and send reply.", e2);
/*     */       }
/* 454 */       dropConnection();
/*     */     }
/*     */   }
/*     */   
/*     */   private void finishMessageData(long size) {
/* 459 */     int numRecipients = this.mEnvelope.getRecipients().size();
/* 460 */     ZimbraPerf.COUNTER_LMTP_RCVD_MSGS.increment();
/* 461 */     ZimbraPerf.COUNTER_LMTP_RCVD_BYTES.increment(size);
/* 462 */     ZimbraPerf.COUNTER_LMTP_RCVD_RCPT.increment(numRecipients);
/*     */     
/* 464 */     int numDelivered = 0;
/* 465 */     for (LmtpAddress recipient : this.mEnvelope.getRecipients()) {
/* 466 */       LmtpReply reply = recipient.getDeliveryStatus();
/* 467 */       sendReply(reply);
/* 468 */       if (reply.success()) {
/* 469 */         numDelivered++;
/*     */       }
/*     */     }
/*     */     
/* 473 */     ZimbraPerf.COUNTER_LMTP_DLVD_MSGS.increment(numDelivered);
/* 474 */     ZimbraPerf.COUNTER_LMTP_DLVD_BYTES.increment(numDelivered * size);
/*     */     
/* 476 */     reset();
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   protected String getAdditionalHeaders()
/*     */   {
/* 484 */     StringBuilder headers = new StringBuilder();
/*     */     
/*     */ 
/* 487 */     if (this.mEnvelope.hasSender()) {
/* 488 */       String sender = this.mEnvelope.getSender().getEmailAddress();
/* 489 */       if (!StringUtil.isNullOrEmpty(sender)) {
/* 490 */         headers.append(String.format("Return-Path: %s\r\n", new Object[] { sender }));
/*     */       }
/*     */     }
/*     */     
/*     */ 
/* 495 */     String localHostname = "unknown";
/*     */     try {
/* 497 */       localHostname = Provisioning.getInstance().getLocalServer().getName();
/*     */     } catch (ServiceException e) {
/* 499 */       ZimbraLog.lmtp.warn("Unable to determine local hostname", e);
/*     */     }
/* 501 */     String timestamp = new MailDateFormat().format(new Date());
/* 502 */     String name = "Received: ";
/* 503 */     String value = String.format("from %s (LHLO %s) (%s) by %s with LMTP; %s", new Object[] { this.mRemoteHostname, this.mLhloArg, this.mRemoteAddress, localHostname, timestamp });
/*     */     
/* 505 */     headers.append(name);
/* 506 */     headers.append(MimeUtility.fold(name.length(), value));
/* 507 */     headers.append("\r\n");
/*     */     
/* 509 */     return headers.toString();
/*     */   }
/*     */   
/*     */   protected abstract void doSTARTTLS(String paramString) throws IOException;
/*     */   
/* 514 */   private boolean tlsConnectionRequired() { if ((this.config.isTLSEnforcedByServer()) && 
/* 515 */       (!this.startedTLS)) {
/* 516 */       return true;
/*     */     }
/*     */     
/* 519 */     return false;
/*     */   }
/*     */   
/*     */   private boolean missingLHLO() {
/* 523 */     if (this.config.isLHLORequired()) {
/* 524 */       return (!this.lhloIssued) || ((this.startedTLS) && (!this.lhloIssuedAfterStartTLS));
/*     */     }
/* 526 */     return false;
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/lmtpserver/LmtpHandler.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */